package com.sunlake.spring.main.common.model.file.service.impl;

import com.sunlake.spring.main.common.model.file.service.FileDownloadService;
import com.sunlake.spring.main.common.utils.JwtTokenUtil;
import com.sunlake.spring.main.common.utils.LoggerUtil;
import com.sunlake.spring.main.model.auth.mapper.UsersMapper;
import com.sunlake.spring.main.common.model.file.mapper.FilesMapper;
import com.sunlake.spring.main.model.counselor.mapper.ResumesMapper;
import com.sunlake.spring.main.model.counselor.po.FilesPO;
import com.sunlake.spring.main.model.counselor.po.ResumesPO;
import com.sunlake.spring.main.model.counselor.service.impl.CounselorApplyServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.ibatis.jdbc.Null;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Service
public class ResumeDownloadServiceImpl implements FileDownloadService {

     private static final Logger log = LoggerUtil.getLogger(CounselorApplyServiceImpl.class);

    // 文件存储路径，从配置文件读取
    @Value("${file.upload-dir}")
    private String UPLOAD_DIR;

    @Value("${file.access-prefix}")
    private String ACCESS_PREFIX;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private FilesMapper filesMapper;

    @Autowired
    private ResumesMapper resumesMapper;

    @Autowired
    private UsersMapper usersMapper;


    /**
     * 获取简历文件的元信息
     */
    @Override
    public Map<String, Object> getFileMeta(Long resumeId) {
        Map<String, Object> meta = new HashMap<>();
        if (resumeId == null) {
            meta.put("acceptRanges", false);
            meta.put("totalSize", null);
            return meta;
        }
        ResumesPO resumesPO = resumesMapper.selectByPrimaryKey(resumeId);

        Long fileId = resumesPO.getFileId();
        if (fileId == null) {
            meta.put("acceptRanges", false);
            meta.put("totalSize", null);
            return meta;
        }
        FilesPO filePO = filesMapper.selectByPrimaryKey(fileId);
        if (filePO == null) {
            meta.put("acceptRanges", false);
            meta.put("totalSize", null);
            return meta;
        }
        String filename = filePO.getFilename();
        String physicalPath = filePO.getFileUrl() != null ? filePO.getFileUrl() : (UPLOAD_DIR + File.separator + filename);
        File physicalFile = new File(physicalPath);
        if (!physicalFile.exists()) {
            meta.put("acceptRanges", false);
            meta.put("totalSize", null);
            return meta;
        }
        meta.put("acceptRanges", true);
        meta.put("totalSize", physicalFile.length());
        meta.put("contentType", detectContentType(filename));
        meta.put("fileName", filename);
        return meta;
    }

    /**
     * 整文件下载
     */
    @Override
    public void downloadFile(Long resumeId, HttpServletResponse response) throws IOException {
        ResumesPO resumesPO = resumesMapper.selectByPrimaryKey(resumeId);
        if (resumesPO == null) { writeJsonError(response, 404, "简历不存在"); return; }
        Long fileId = resumesPO.getFileId();
        if (fileId == null) { writeJsonError(response, 404, "文件记录不存在"); return; }
        FilesPO filePO = filesMapper.selectByPrimaryKey(fileId);
        if (filePO == null) { writeJsonError(response, 404, "文件记录不存在"); return; }
        String filename = filePO.getFilename();
        File physicalFile = new File(filePO.getFileUrl() != null ? filePO.getFileUrl() : (UPLOAD_DIR + File.separator + filename));
        if (!physicalFile.exists()) { writeJsonError(response, 404, "文件不存在"); return; }
        response.setStatus(200);
        response.setContentType(detectContentType(filename));
        response.setHeader("Accept-Ranges", "bytes");
        response.setHeader("Content-Length", String.valueOf(physicalFile.length()));
        setContentDisposition(response, filename);
        try (java.io.InputStream in = new java.io.FileInputStream(physicalFile); java.io.OutputStream out = response.getOutputStream()) {
            byte[] buf = new byte[8192]; int len; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); }
            out.flush();
        }
    }

    /**
     * 范围下载（断点续传）
     */
    @Override
    public void downloadFileRange(Long resumeId, long start, long end, HttpServletResponse response) throws IOException {
        ResumesPO resumesPO = resumesMapper.selectByPrimaryKey(resumeId);
        if (resumesPO == null) { writeJsonError(response, 404, "简历不存在"); return; }
        Long fileId = resumesPO.getFileId();
        if (fileId == null) { writeJsonError(response, 404, "文件记录不存在"); return; }
        FilesPO filePO = filesMapper.selectByPrimaryKey(fileId);
        if (filePO == null) { writeJsonError(response, 404, "文件记录不存在"); return; }
        String filename = filePO.getFilename();
        File physicalFile = new File(filePO.getFileUrl() != null ? filePO.getFileUrl() : (UPLOAD_DIR + File.separator + filename));
        if (!physicalFile.exists()) { writeJsonError(response, 404, "文件不存在"); return; }
        long fileLength = physicalFile.length();
        // 规范化范围
        if (start < 0) start = 0;
        if (end < 0 || end >= fileLength) end = fileLength - 1;
        if (start > end) { writeJsonError(response, 416, "范围无效"); return; }
        long contentLength = end - start + 1;
        response.setStatus(206);
        response.setContentType(detectContentType(filename));
        response.setHeader("Accept-Ranges", "bytes");
        response.setHeader("Content-Length", String.valueOf(contentLength));
        response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
        setContentDisposition(response, filename);
        try (RandomAccessFile raf = new RandomAccessFile(physicalFile, "r"); java.io.OutputStream out = response.getOutputStream()) {
            raf.seek(start);
            byte[] buf = new byte[8192]; long remaining = contentLength; while (remaining > 0) { int read = raf.read(buf, 0, (int) Math.min(buf.length, remaining)); if (read == -1) break; out.write(buf, 0, read); remaining -= read; }
            out.flush();
        }
    }

    // ================== 辅助方法 ==================
    private void writeJsonError(HttpServletResponse response, int status, String message) throws IOException {
        response.setStatus(status);
        response.setContentType("application/json;charset=UTF-8");
        String json = "{\"success\":false,\"code\":" + status + ",\"message\":\"" + message + "\"}";
        response.getWriter().write(json);
    }

    private void setContentDisposition(HttpServletResponse response, String filename) {
        try {
            String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encoded + "\"; filename*=UTF-8''" + encoded);
        } catch (Exception e) {
            log.debug("设置Content-Disposition失败: {}", e.getMessage());
        }
    }

    private String detectContentType(String filename) {
        if (filename == null) return "application/octet-stream";
        String lower = filename.toLowerCase(Locale.ROOT);
        if (lower.endsWith(".pdf")) return "application/pdf";
        if (lower.endsWith(".docx")) return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        if (lower.endsWith(".doc")) return "application/msword";
        if (lower.endsWith(".txt")) return "text/plain";
        return "application/octet-stream";
    }

}
